home *** CD-ROM | disk | FTP | other *** search
- Subject: v20i024: Deliver, flexible email delivery system, Part02/04
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Chip Salzenberg <chip@ateng.com>
- Posting-number: Volume 20, Issue 24
- Archive-name: deliver2.0/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: config.h context.h deliver.h dest.h patchlevel.h misc.h
- # context.c copymsg.c
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'config.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'config.h'\"
- else
- echo shar: Extracting \"'config.h'\" \(6654 characters\)
- sed "s/^X//" >'config.h' <<'END_OF_FILE'
- X/* $Header: config.h,v 2.2 89/06/09 13:07:38 network Exp $
- X *
- X * Deliver configuration.
- X *
- X * $Log: config.h,v $
- X * Revision 2.2 89/06/09 13:07:38 network
- X * Adapt to BSD quirks.
- X *
- X * Revision 2.1 89/06/09 12:25:11 network
- X * Update RCS revisions.
- X *
- X * Revision 1.11 89/06/09 12:23:38 network
- X * Baseline for 2.0 release.
- X *
- X */
- X
- X/*----------------------------------------------------------------------
- X * SCO Xenix System V compilers define M_SYSV, which implies USG.
- X */
- X
- X#ifdef M_SYSV
- X#ifndef USG
- X#define USG
- X#endif
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * Trusted users.
- X * Deliver permits "trusted" users to specify delivery filenames
- X * without renouncing setuid privileges. Essentially, these users
- X * are given the root password. Beware!
- X */
- X
- X#define TRUSTED_USERS "root", "uucp"
- X
- X/*----------------------------------------------------------------------
- X * Signal function type.
- X * Signal catching routines have this return value.
- X * (For System V Release 3.0 or later, use "void".)
- X */
- X
- X#ifdef USG
- X# define SIGTYPE void
- X#else
- X# define SIGTYPE int
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * Signal function declaration.
- X * Define this if your <signal.h> doesn't declare signal() correctly.
- X */
- X
- X/* #define DECLARE_SIGNAL */
- X
- X/*----------------------------------------------------------------------
- X * Signal flag type.
- X * Variables of this type may be set by signal catching routines.
- X */
- X
- X#ifdef __STDC__
- X#define SIGFLAG sig_atomic_t
- X#else
- X#define SIGFLAG short /* or "volatile short" for aggressive optimizers */
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * Various kinds of mailbox locking.
- X * You may define one or both of ML_DOTLOCK and ML_DOTMLK.
- X * You may define no more than one of ML_FCNTL, ML_LOCKF and ML_LOCKING.
- X *
- X * File creation locking:
- X * ML_DOTLOCK create <mailbox>.lock (most systems except BSD4.3)
- X * ML_DOTMLK create /tmp/<basename>.mlk (Xenix)
- X *
- X * Kernel record locking:
- X * ML_FCNTL lock with fcntl(F_SETLKW) (SVID systems only)
- X * ML_LOCKF lock with lockf(F_LOCK) (SVID systems only)
- X * ML_LOCKING lock with locking(LK_LOCK) (Xenix systems only)
- X */
- X
- X#ifdef M_XENIX
- X#define ML_DOTMLK
- X#define ML_LOCKING
- X#else
- X#define ML_DOTLOCK
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * Maximum filename length.
- X * Note that this is for _filenames_, not _pathnames_.
- X * For AT&T file systems, the usual value is 14.
- X * For Berzerkley file systems, use something big like 255.
- X */
- X
- X#ifdef BSD
- X#define MAX_NAMESIZE 255
- X#else
- X#define MAX_NAMESIZE 14
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * How to get the host name.
- X * Define one.
- X *
- X * HOSTFILE file containing name (Xenix)
- X * UNAME uname() (System V)
- X * GETHOSTNAME gethostname() (BSD)
- X * HOSTNAME host name string (V7)
- X */
- X
- X#ifdef M_XENIX
- X#define HOSTFILE "/etc/systemid"
- X#else
- X#ifdef USG
- X#define UNAME
- X#else
- X#ifdef BSD
- X#define GETHOSTNAME
- X#else
- X#define HOSTNAME "cleese"
- X#endif
- X#endif
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * Is <varargs.h> or <stdarg.h> available?
- X */
- X
- X#ifdef __STDC__
- X#define HAS_STDARG
- X#else
- X#ifdef USG
- X#define HAS_VARARGS
- X#else
- X#ifdef BSD
- X#define HAS_VARARGS
- X#endif
- X#endif
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * Are vprintf() and friends available?
- X */
- X
- X#ifdef USG
- X#define HAS_VPRINTF
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * Is putenv() available?
- X */
- X
- X#ifdef USG
- X#define HAS_PUTENV
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * Is getopt() available?
- X */
- X
- X#ifdef USG
- X#define HAS_GETOPT
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * Is setvbuf() backwards?
- X * Note: this is true for SCO Xenix Development System 2.2.
- X */
- X
- X/* #define REVERSE_SETVBUF */
- X
- X/*----------------------------------------------------------------------
- X * Name of shell used to execute delivery files.
- X */
- X
- X#define SHELL "/bin/sh"
- X
- X/*----------------------------------------------------------------------
- X * Characters that may not appear in addresses.
- X * (This string should include all metacharacters for your chosen shell.)
- X */
- X
- X#define SANITIZE "$*?=\\`'\"|^&;{}()<> \t\n"
- X
- X/*----------------------------------------------------------------------
- X * Standard mailbox location.
- X *
- X * Define either MBX_NAME or MBOX_DIR.
- X * If MBX_NAME is defined, then the default mailbox is a file with
- X * that name in the user's home directory.
- X * If MBX_DIR is defined, then the default mailbox is a file in that
- X * directory with the same name as the user.
- X *
- X * Define MBX_GROUP if all mailboxes must be owned by a specific group.
- X * (System V requires this feature.) If MBX_GROUP is not defined,
- X * mailboxes will have their groups set to the recipients' default group.
- X *
- X * Define MBX_MODE to the file access modes for new mailboxes.
- X * (System V requires group write permissions, i.e. 0020.)
- X */
- X
- X#if defined(USG) && !defined(M_XENIX)
- X/* #define MBX_NAME "mbox" */
- X#define MBX_DIR "/usr/mail"
- X#define MBX_MODE 0660
- X#define MBX_GROUP "mail"
- X#else
- X/* #define MBX_NAME "mbox" */
- X#define MBX_DIR "/usr/spool/mail"
- X#define MBX_MODE 0600
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * Names of delivery files.
- X *
- X * SYS_DELIVER system-wide delivery file
- X * POST_DELIVER post-user delivery file
- X * USER_DELIVER user delivery file (in user's home directory)
- X */
- X
- X#define SYS_DELIVER "/usr/local/lib/deliver.sys"
- X#define POST_DELIVER "/usr/local/lib/deliver.post"
- X#define USER_DELIVER ".deliver"
- X
- X/*----------------------------------------------------------------------
- X * Environment variables passed to child processes.
- X */
- X
- X#define ENV_DFLAGS "DELFLAGS" /* Flags: [-[Avdt]] */
- X#define ENV_SYSDEL "SYSDELFILE" /* System delivery file */
- X#define ENV_POSTDEL "POSTDELFILE" /* Post-user delivery file */
- X#define ENV_USERDEL "USERDELFILE" /* User delivery file */
- X
- X#define ENV_HOSTNAME "HOSTNAME" /* Name of this host */
- X#define ENV_SENDER "SENDER" /* Message sender */
- X#define ENV_HEADER "HEADER" /* Message header file */
- X#define ENV_BODY "BODY" /* Message body file */
- END_OF_FILE
- if test 6654 -ne `wc -c <'config.h'`; then
- echo shar: \"'config.h'\" unpacked with wrong size!
- fi
- # end of 'config.h'
- fi
- if test -f 'context.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'context.h'\"
- else
- echo shar: Extracting \"'context.h'\" \(527 characters\)
- sed "s/^X//" >'context.h' <<'END_OF_FILE'
- X/* $Header: context.h,v 2.1 89/06/09 12:25:15 network Exp $
- X *
- X * User context, as found in /etc/passwd.
- X *
- X * $Log: context.h,v $
- X * Revision 2.1 89/06/09 12:25:15 network
- X * Update RCS revisions.
- X *
- X * Revision 1.3 89/06/09 12:23:40 network
- X * Baseline for 2.0 release.
- X *
- X */
- X
- X/*----------------------------------------------------------------------
- X * The context structure.
- X */
- X
- X#define CONTEXT struct context
- XCONTEXT {
- X CONTEXT *ct_next;
- X int ct_uid;
- X int ct_gid;
- X char *ct_name;
- X char *ct_home;
- X};
- END_OF_FILE
- if test 527 -ne `wc -c <'context.h'`; then
- echo shar: \"'context.h'\" unpacked with wrong size!
- fi
- # end of 'context.h'
- fi
- if test -f 'deliver.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'deliver.h'\"
- else
- echo shar: Extracting \"'deliver.h'\" \(3237 characters\)
- sed "s/^X//" >'deliver.h' <<'END_OF_FILE'
- X/* $Header: deliver.h,v 2.1 89/06/09 12:25:21 network Exp $
- X *
- X * General pull-it-together include file.
- X *
- X * $Log: deliver.h,v $
- X * Revision 2.1 89/06/09 12:25:21 network
- X * Update RCS revisions.
- X *
- X * Revision 1.10 89/06/09 12:23:44 network
- X * Baseline for 2.0 release.
- X *
- X */
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <sys/types.h>
- X
- X#include "config.h"
- X#include "misc.h"
- X#include "context.h"
- X#include "dest.h"
- X
- X/*----------------------------------------------------------------------
- X * Global data
- X */
- X
- Xextern int verbose; /* Print debugging messages? */
- Xextern int dryrun; /* Are we making a dry run? */
- Xextern int rundfiles; /* Run delivery files at all? */
- Xextern int printaddrs; /* Address resolution only? */
- Xextern int leavetemps; /* Leave temp files for later perusal */
- Xextern int boxdelivery; /* Args are mailboxes, not addresses */
- Xextern char *sender; /* Who is sending this message? */
- X
- Xextern char *progname; /* Name this program was invoked under */
- Xextern char *hostname; /* Name of this host */
- X
- Xextern char *sys_deliver; /* Systemwide delivery file */
- Xextern char *post_deliver; /* Post-user delivery file */
- Xextern char *user_deliver; /* User delivery file */
- Xextern char *shell; /* Shell used to run delivery files */
- X
- Xextern int eff_uid; /* Returned by geteuid() */
- Xextern int eff_gid; /* Returned by getegid() */
- Xextern int real_uid; /* Returned by getuid() */
- Xextern int real_gid; /* Returned by getgid() */
- X
- Xextern CONTEXT *eff_ct; /* Context of effective uid */
- Xextern CONTEXT *real_ct; /* Context of real uid */
- X
- Xextern int trust_user; /* Do we trust the user that called us? */
- Xextern int trust_delfiles; /* Do we trust the delivery files? */
- X
- X/* Temp file indices: */
- X#define T_HDR 0 /* Message header */
- X#define T_BODY 1 /* Message body */
- X#define T_HDRCOPY 2 /* Copy of message header */
- X#define T_BODYCOPY 3 /* Copy of message body */
- X#define T_MAX 4 /* Number of temp files */
- X
- Xextern char *ttype[T_MAX]; /* Temp file types (for messages) */
- Xextern char *tfile[T_MAX]; /* Temp file names */
- Xextern char *tenv[T_MAX]; /* Temp file environment names */
- Xextern int tfd[T_MAX]; /* Temp file fd's */
- X
- Xextern SIGFLAG got_sig; /* We caught a signal and should exit */
- X
- X/*----------------------------------------------------------------------
- X * Global functions
- X */
- X
- Xchar *basename();
- Xchar *gethost();
- Xchar *copystr();
- Xchar *derrmsg();
- Xchar *zalloc();
- Xchar *srealloc();
- X
- XCONTEXT *name_context();
- XCONTEXT *uid_context();
- X
- XFILE *ct_popenv();
- Xint ct_pclose();
- X
- XDEST *dest();
- XDEST *first_dest();
- XDEST *next_dest();
- X
- Xtime_t unctime();
- END_OF_FILE
- if test 3237 -ne `wc -c <'deliver.h'`; then
- echo shar: \"'deliver.h'\" unpacked with wrong size!
- fi
- # end of 'deliver.h'
- fi
- if test -f 'dest.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'dest.h'\"
- else
- echo shar: Extracting \"'dest.h'\" \(2503 characters\)
- sed "s/^X//" >'dest.h' <<'END_OF_FILE'
- X/* $Header: dest.h,v 2.1 89/06/09 12:25:23 network Exp $
- X *
- X * Description of a mail destination and its state.
- X *
- X * $Log: dest.h,v $
- X * Revision 2.1 89/06/09 12:25:23 network
- X * Update RCS revisions.
- X *
- X * Revision 1.3 89/06/09 12:23:48 network
- X * Baseline for 2.0 release.
- X *
- X */
- X
- X/*----------------------------------------------------------------------
- X * Destination class.
- X */
- X
- Xtypedef enum {
- X CL_USER, /* User name, no mailbox */
- X CL_MBOX, /* User name, with mailbox name */
- X CL_UUCP /* UUCP address (bang path) */
- X} DCLASS;
- X
- X/*----------------------------------------------------------------------
- X * Destination state.
- X */
- X
- Xtypedef enum {
- X ST_WORKING, /* the "normal" state */
- X ST_HOLD, /* on hold during expansion */
- X ST_DONE, /* all processing complete */
- X ST_ERROR /* "something is horribly wrong" */
- X} DSTATE;
- X
- X/*----------------------------------------------------------------------
- X * Types of destination errors.
- X */
- X
- Xtypedef enum {
- X E_IVADDR, /* invalid address string */
- X E_NSUSER, /* no such user */
- X E_NSHOST, /* no such host (UUCP addresses) */
- X E_CTPERM, /* no permissions for that context */
- X E_CTLOST, /* context lost (should never happen) */
- X E_MBOX, /* can't write to mailbox */
- X E_UUX /* can't pipe to uux */
- X} DERROR;
- X
- X/*----------------------------------------------------------------------
- X * Structure describing a mail destination.
- X */
- X
- X#define DEST struct dest
- XDEST {
- X DEST *d_next; /* next destination in the chain */
- X DEST *d_prev; /* previous destination in the chain */
- X DCLASS d_class; /* destination class */
- X DSTATE d_state; /* destination state */
- X DERROR d_error; /* error message (if state is ERROR) */
- X int d_dfdone; /* boolean -- delivery file was run */
- X char *d_name; /* context for delivery */
- X char *d_mailbox; /* mailbox name or NULL for default */
- X};
- X
- X/*----------------------------------------------------------------------
- X * Action macros.
- X */
- X
- X#define dest_err(d,m) ((d)->d_state = ST_ERROR, (d)->d_error = (m))
- END_OF_FILE
- if test 2503 -ne `wc -c <'dest.h'`; then
- echo shar: \"'dest.h'\" unpacked with wrong size!
- fi
- # end of 'dest.h'
- fi
- if test -f 'patchlevel.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'patchlevel.h'\"
- else
- echo shar: Extracting \"'patchlevel.h'\" \(21 characters\)
- sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
- X#define PATCHLEVEL 0
- END_OF_FILE
- if test 21 -ne `wc -c <'patchlevel.h'`; then
- echo shar: \"'patchlevel.h'\" unpacked with wrong size!
- fi
- # end of 'patchlevel.h'
- fi
- if test -f 'misc.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'misc.h'\"
- else
- echo shar: Extracting \"'misc.h'\" \(2246 characters\)
- sed "s/^X//" >'misc.h' <<'END_OF_FILE'
- X/* $Header: misc.h,v 2.1 89/06/09 12:25:35 network Exp $
- X *
- X * Miscellaneous definitions.
- X *
- X * $Log: misc.h,v $
- X * Revision 2.1 89/06/09 12:25:35 network
- X * Update RCS revisions.
- X *
- X * Revision 1.7 89/06/09 12:23:56 network
- X * Baseline for 2.0 release.
- X *
- X */
- X
- X/*
- X * Non-portable include files
- X */
- X
- X#ifdef USG
- X#include <fcntl.h>
- X#include <string.h>
- X#include <memory.h>
- X#endif
- X
- X#ifdef BSD
- X#include <strings.h>
- X#include <sys/file.h>
- X#endif
- X
- X/*
- X * Constants
- X */
- X
- X#ifdef NULL
- X#undef NULL
- X#endif
- X#define NULL 0 /* The One True NULL */
- X
- X#define FALSE 0
- X#define TRUE 1
- X
- X#ifndef O_RDONLY
- X#define O_RDONLY 0
- X#define O_WRONLY 1
- X#define O_RDWR 2
- X#endif
- X
- X/*
- X * Macros.
- X */
- X
- X/* Length parameter for fgets() on given buffer. */
- X
- X#define GETSIZE(buf) (int) (sizeof(buf) - 1)
- X
- X/*
- X * Public data.
- X */
- X
- Xextern char **environ;
- X
- X/*
- X * Common library functions.
- X */
- X
- Xextern char *ctime();
- Xextern char *getenv();
- Xextern char *malloc();
- Xextern char *realloc();
- Xextern char *mktemp();
- Xextern int putenv();
- Xextern long lseek();
- Xextern long time();
- Xextern void free();
- X
- X#ifdef DECLARE_SIGNAL
- Xextern SIGTYPE (*signal())();
- X#endif
- X
- X/*
- X * String search functions.
- X */
- X
- X#ifndef USG
- X
- X#ifndef BSD
- Xextern char *index();
- Xextern char *rindex();
- X#endif /* not BSD */
- X
- X#define strchr index
- X#define strrchr rindex
- X
- X#endif
- X
- X/*
- X * Memory copy and zero.
- X */
- X
- X#ifdef USG
- X#define Copy(d,s,n) (void) memcpy(d,s,n)
- X#define Zero(d,n) (void) memset(d,0,(int)(n))
- X#else /* not USG */
- X#ifdef BSD
- X#define Copy(d,s,n) bcopy(s,d,n)
- X#define Zero(d,n) bzero(d,n)
- X#else /* not BSD */
- X#define MEMFUNCS /* define Copy() and Zero() in sysdep.c */
- X#endif /* not BSD */
- X#endif /* not USG */
- X
- X/*
- X * Line-buffering on stdio files.
- X */
- X
- X#ifdef USG
- X
- Xextern int setvbuf();
- X
- X#ifdef REVERSE_SETVBUF
- X#define Linebuf(f) (void) setvbuf(f, _IOLBF, (char *)NULL, BUFSIZ)
- X#else
- X#define Linebuf(f) (void) setvbuf(f, (char *)NULL, _IOLBF, BUFSIZ)
- X#endif
- X
- X#else /* not USG */
- X#ifdef BSD
- X
- Xextern int setlinebuf();
- X
- X#define Linebuf(f) (void) setlinebuf(f)
- X
- X#else /* not BSD */
- X
- X#define Linebuf(f) /* can't do it */
- X
- X#endif /* not BSD */
- X#endif /* not USG */
- END_OF_FILE
- if test 2246 -ne `wc -c <'misc.h'`; then
- echo shar: \"'misc.h'\" unpacked with wrong size!
- fi
- # end of 'misc.h'
- fi
- if test -f 'context.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'context.c'\"
- else
- echo shar: Extracting \"'context.c'\" \(2517 characters\)
- sed "s/^X//" >'context.c' <<'END_OF_FILE'
- X/* $Header: context.c,v 2.1 89/06/09 12:25:13 network Exp $
- X *
- X * User context manager.
- X * This module exists for efficiency reasons; I could just call getpwnam()
- X * every time I need context info.
- X *
- X * $Log: context.c,v $
- X * Revision 2.1 89/06/09 12:25:13 network
- X * Update RCS revisions.
- X *
- X * Revision 1.5 89/06/09 12:23:39 network
- X * Baseline for 2.0 release.
- X *
- X */
- X
- X#include "deliver.h"
- X#include <pwd.h>
- X#include <grp.h>
- X
- Xextern struct passwd *getpwnam();
- Xextern struct passwd *getpwuid();
- Xextern struct group *getgrnam();
- Xextern struct group *getgrgid();
- X
- X/*
- X * Local functions.
- X */
- X
- Xstatic CONTEXT *new_context();
- X
- X/*
- X * Local data.
- X */
- X
- Xstatic CONTEXT *ctlist; /* Chain of CONTEXT structures. */
- X
- X/*----------------------------------------------------------------------
- X * Look up a context by user name.
- X */
- X
- XCONTEXT *
- Xname_context(name)
- Xchar *name;
- X{
- X struct passwd *pw;
- X CONTEXT *ct;
- X
- X for (ct = ctlist; ct; ct = ct->ct_next)
- X {
- X if (strcmp(ct->ct_name, name) == 0)
- X return ct;
- X }
- X
- X if ((pw = getpwnam(name)) == NULL)
- X return NULL;
- X
- X return new_context(pw);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Look up a context by user ID.
- X */
- X
- XCONTEXT *
- Xuid_context(uid)
- Xint uid;
- X{
- X struct passwd *pw;
- X CONTEXT *ct;
- X
- X for (ct = ctlist; ct; ct = ct->ct_next)
- X {
- X if (ct->ct_uid == uid)
- X return ct;
- X }
- X
- X if ((pw = getpwuid(uid)) == NULL)
- X return NULL;
- X
- X return new_context(pw);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Local function -- create a new context structure and return
- X * its address.
- X */
- X
- Xstatic CONTEXT *
- Xnew_context(pw)
- Xstruct passwd *pw;
- X{
- X CONTEXT *ct;
- X
- X ct = (CONTEXT *) zalloc(sizeof(CONTEXT));
- X ct->ct_uid = pw->pw_uid;
- X ct->ct_gid = pw->pw_gid;
- X ct->ct_name = copystr(pw->pw_name);
- X ct->ct_home = copystr(pw->pw_dir);
- X
- X ct->ct_next = ctlist;
- X ctlist = ct;
- X
- X return ct;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Report whether is is possible or not to enter the given context.
- X */
- X
- Xint
- Xok_context(ct)
- XCONTEXT *ct;
- X{
- X if (! ct)
- X return FALSE;
- X
- X if (eff_uid == 0
- X || ((real_uid == ct->ct_uid) && (real_gid == ct->ct_gid)))
- X return TRUE;
- X else
- X return FALSE;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Look up a group ID by name.
- X */
- X
- X#ifdef MBX_GROUP
- X
- Xint
- Xgroup_id(name)
- Xchar *name;
- X{
- X struct group *grp;
- X
- X if ((grp = getgrnam(name)) == NULL)
- X return -1;
- X
- X return grp->gr_gid;
- X}
- X
- X#endif /* MBX_GROUP */
- END_OF_FILE
- if test 2517 -ne `wc -c <'context.c'`; then
- echo shar: \"'context.c'\" unpacked with wrong size!
- fi
- # end of 'context.c'
- fi
- if test -f 'copymsg.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'copymsg.c'\"
- else
- echo shar: Extracting \"'copymsg.c'\" \(8775 characters\)
- sed "s/^X//" >'copymsg.c' <<'END_OF_FILE'
- X/* $Header: copymsg.c,v 2.1 89/06/09 12:25:16 network Exp $
- X *
- X * Take the message from standard input and write it to two temp files,
- X * one for the header (including the empty line) and one for the body.
- X *
- X * $Log: copymsg.c,v $
- X * Revision 2.1 89/06/09 12:25:16 network
- X * Update RCS revisions.
- X *
- X * Revision 1.9 89/06/09 12:23:40 network
- X * Baseline for 2.0 release.
- X *
- X */
- X
- X#include "deliver.h"
- X
- X/*
- X * Macros.
- X */
- X
- X/* Does a string start with "From "? */
- X
- X#define ISFROM(p) ((p)[0] == 'F' && (p)[1] == 'r' && (p)[2] == 'o' \
- X && (p)[3] == 'm' && (p)[4] == ' ')
- X
- X/*
- X * Local functions.
- X */
- X
- Xstatic char *tempfile();
- Xstatic int tcreate();
- X
- X/*----------------------------------------------------------------------
- X * Copy the message on the standard input to two temp files:
- X * one for the header and one for the body.
- X */
- X
- Xint
- Xcopy_message()
- X{
- X char buf[BUFSIZ];
- X FILE *dfp[T_MAX];
- X char *p, *from_line, *fsender, *fdate, *fremote;
- X int t, b, empty_line;
- X int ret = 0;
- X
- X /*
- X * Create temporary files to hold the header and message body.
- X */
- X
- X for (t = T_HDR; t <= T_BODY; ++t)
- X {
- X int fd;
- X
- X tfile[t] = tempfile();
- X if ((tfd[t] = tcreate(tfile[t])) == -1)
- X return -1;
- X
- X if ((fd = dup(tfd[t])) == -1)
- X {
- X syserr("dup %s fd", ttype[t]);
- X return -1;
- X }
- X (void) lseek(fd, 0L, 0);
- X if ((dfp[t] = fdopen(fd, "r+")) == NULL)
- X {
- X error("can't fdopen %s fd", ttype[t]);
- X return -1;
- X }
- X }
- X
- X /* Debugging message for later examination of temp files. */
- X
- X if (verbose)
- X {
- X message("header=%s, body=%s\n",
- X tfile[T_HDR], tfile[T_BODY]);
- X }
- X
- X /*
- X * If there is a From_ line, find the sender name therein.
- X */
- X
- X from_line = NULL;
- X fsender = fdate = fremote = NULL;
- X
- X b = (fgets(buf, GETSIZE(buf), stdin) ? TRUE : FALSE);
- X
- X if (b && ISFROM(buf) && (p = strchr(buf, '\n')) != NULL)
- X {
- X b = FALSE;
- X
- X /* Make a mungable copy of the From_ line */
- X
- X from_line = copystr(buf);
- X if ((p = strchr(from_line, '\n')) != NULL)
- X *p = 0;
- X
- X /* Find sender */
- X
- X p = from_line + 5;
- X while (*p && isspace(*p))
- X ++p;
- X fsender = p;
- X while (*p && !isspace(*p))
- X ++p;
- X if (*p)
- X *p++ = 0;
- X
- X /* Date received should be around here somewhere */
- X
- X fdate = p;
- X
- X /* Find 'remote from' phrase (if any) */
- X
- X for (; (p = strchr(p, 'r')) != NULL; ++p)
- X {
- X if (strncmp(p, "remote from", 11) == 0)
- X {
- X *p = 0;
- X p += 11;
- X while (*p && isspace(*p))
- X ++p;
- X if (*p)
- X fremote = p;
- X break;
- X }
- X }
- X
- X /*
- X * Advance to first non-space in date.
- X * If there is no date, clear the date pointer.
- X */
- X
- X while (*fdate && isspace(*fdate))
- X ++fdate;
- X if (*fdate == 0)
- X fdate = NULL;
- X
- X /*
- X * If sender is missing, or if date is invalid,
- X * we consider the entire From_ line invalid.
- X */
- X
- X if (*fsender == 0
- X || (fdate != NULL && unctime(fdate) == -1) )
- X {
- X /* Ignore everything we found. */
- X
- X fsender = fdate = fremote = NULL;
- X
- X /* Print invalid From_ line in a harmless way. */
- X
- X (void) strcpy(from_line, buf);
- X (void) strcpy(buf, "Invalid-UUCP-From: ");
- X (void) strcat(buf, from_line);
- X b = TRUE;
- X }
- X }
- X
- X /*
- X * Write a From_ line to the header file.
- X */
- X
- X /* if caller specified sender, use it */
- X if (sender)
- X ; /* fine */
- X
- X /* else if we found a From_ line, use it */
- X else if (fsender)
- X {
- X if (fremote)
- X {
- X sender = zalloc(strlen(fremote) + sizeof("!")
- X + strlen(fsender));
- X (void) sprintf(sender, "%s!%s", fremote, fsender);
- X }
- X else
- X sender = copystr(fsender);
- X }
- X
- X /* else use our real ID */
- X else
- X sender = real_ct->ct_name;
- X
- X /* debugging message */
- X
- X if (verbose)
- X message("copy_msg: sender is \"%s\"\n", sender);
- X
- X /*
- X * Finally! Write the From_ line.
- X */
- X
- X (void) fputs("From ", dfp[T_HDR]);
- X (void) fputs(sender, dfp[T_HDR]);
- X (void) fputc(' ', dfp[T_HDR]);
- X if (fdate)
- X {
- X (void) fputs(fdate, dfp[T_HDR]);
- X (void) fputc('\n', dfp[T_HDR]);
- X }
- X else
- X {
- X time_t now;
- X
- X (void) time(&now);
- X (void) fputs(ctime(&now), dfp[T_HDR]);
- X }
- X
- X /*
- X * Free the From_ line if we allocated a copy of it.
- X */
- X
- X if (from_line)
- X free(from_line);
- X
- X /*
- X * Copy the rest of the header (if any).
- X */
- X
- X for (; !feof(stdin) && !ferror(stdin); b = FALSE)
- X {
- X if (!b)
- X {
- X if (fgets(buf, GETSIZE(buf), stdin))
- X b = TRUE;
- X else
- X break;
- X }
- X
- X /* Empty line means "end of header" */
- X
- X if (buf[0] == '\n')
- X {
- X b = FALSE; /* Don't put this line in the body. */
- X break;
- X }
- X
- X /*
- X * A line too long to fit in buf[] can't be a header line.
- X * At least, that's my opinion... :-)
- X */
- X
- X if (!strchr(buf, '\n'))
- X break;
- X
- X /*
- X * If line begins with whitespace, it's a continuation.
- X * Else if line begins with From_ or '>', prepend '>'.
- X * Else if line doesn't look like a header, this must
- X * be the beginning of the body.
- X */
- X
- X if (isspace(buf[0]))
- X ; /* continuation */
- X else if (ISFROM(buf) || (buf[0] == '>'))
- X (void) fputc('>', dfp[T_HDR]);
- X else
- X {
- X /* look for the colon on a header label */
- X
- X p = buf;
- X while (isalpha(*p) || *p == '-')
- X ++p;
- X if ((p == buf) || (*p != ':'))
- X break; /* Not a header line! */
- X }
- X
- X /* Write the line to the header file. */
- X
- X (void) fputs(buf, dfp[T_HDR]);
- X }
- X
- X /*
- X * End the header file with a blank line.
- X * This enables us to simply concatenate it with the body file
- X * to produce a valid message.
- X */
- X
- X (void) fputc('\n', dfp[T_HDR]);
- X
- X /*
- X * Copy the body (if any).
- X */
- X
- X empty_line = FALSE;
- X for (; !feof(stdin) && !ferror(stdin); b = FALSE)
- X {
- X if (!b)
- X {
- X if (fgets(buf, GETSIZE(buf), stdin))
- X b = TRUE;
- X else
- X break;
- X }
- X
- X if (ISFROM(buf))
- X (void) fputc('>', dfp[T_BODY]);
- X (void) fputs(buf, dfp[T_BODY]);
- X
- X empty_line = (buf[0] == '\n');
- X
- X /*
- X * Output the rest of a very long line.
- X * We do this here, instead of going around the loop,
- X * in order to avoid misinterpreting From_ strings
- X * that may be found in long lines.
- X */
- X
- X while (!strchr(buf, '\n')
- X && !feof(stdin)
- X && !ferror(stdin)
- X && fgets(buf, GETSIZE(buf), stdin))
- X (void) fputs(buf, dfp[T_BODY]);
- X }
- X
- X /* Ensure that the body ends with a blank line. */
- X
- X if (! empty_line)
- X (void) fputc('\n', dfp[T_BODY]);
- X
- X /*
- X * If we encountered any trouble writing to the temp files,
- X * let's not keep it secret.
- X */
- X
- X for (t = T_HDR; t <= T_BODY; ++t)
- X {
- X if (ferror(dfp[t]))
- X {
- X error("error writing to %s file %s\n",
- X ttype[t], tfile[t]);
- X ret = -1;
- X }
- X
- X (void) fclose(dfp[t]);
- X }
- X
- X /* Return error/success. */
- X
- X return ret;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Create another copy of each temp file, for security reasons.
- X * Also, put their names in the environment.
- X */
- X
- Xint
- Xcopy_again()
- X{
- X int r, t;
- X
- X for (r = T_HDR, t = T_HDRCOPY; r <= T_BODY; ++r, ++t)
- X {
- X /*
- X * If the file exists, remove it but keep its name.
- X * Otherwise, make a new name and put that name in
- X * the environment.
- X */
- X
- X if (tfile[t])
- X (void) unlink(tfile[t]);
- X else
- X {
- X tfile[t] = tempfile();
- X if (tenv[t])
- X alloc_env(tenv[t], tfile[t]);
- X }
- X
- X /*
- X * Create the file and copy the contents of the
- X * original file to it.
- X */
- X
- X if (tfd[t] != -1)
- X (void) close(tfd[t]);
- X
- X if ((tfd[t] = tcreate(tfile[t])) == -1)
- X return -1;
- X
- X (void) lseek(tfd[r], 0L, 0);
- X if (copyfd(tfd[r], tfd[t]) < 0)
- X return -1;
- X }
- X
- X if (verbose)
- X {
- X message("copy_again: header to %s, body to %s\n",
- X tfile[T_HDRCOPY], tfile[T_BODYCOPY]);
- X }
- X
- X return 0;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Copy a file via file descriptors.
- X */
- X
- Xint
- Xcopyfd(src_fd, dest_fd)
- Xint src_fd;
- Xint dest_fd;
- X{
- X char buf[BUFSIZ];
- X int rd, wr;
- X
- X while ((rd = read(src_fd, buf, sizeof(buf))) > 0)
- X {
- X if ((wr = write(dest_fd, buf, (unsigned) rd)) != rd)
- X {
- X if (wr == -1)
- X syserr("can't write in copyfd");
- X else
- X error("write error -- disk full?\n");
- X return -1;
- X }
- X }
- X
- X return 0;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Return a pointer to a temporary filename, or NULL if error.
- X */
- X
- Xstatic char *
- Xtempfile()
- X{
- X static char template[] = "/tmp/dl.XXXXXX";
- X char *f;
- X
- X f = zalloc(32);
- X (void) strcpy(f, template);
- X if (mktemp(f) == NULL)
- X {
- X error("can't create temporary file");
- X return NULL;
- X }
- X return f;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Create a file, or complain if it doesn't work.
- X */
- X
- Xstatic int
- Xtcreate(name)
- Xchar *name;
- X{
- X int fd;
- X
- X#ifdef O_CREAT
- X fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0);
- X#else
- X fd = creat(name, 0);
- X#endif
- X if (fd == -1)
- X {
- X syserr("can't create %s", name);
- X return -1;
- X }
- X
- X#ifndef O_CREAT
- X (void) close(fd);
- X if ((fd = open(name, 2)) == -1)
- X {
- X syserr("can't re-open %s", name);
- X return -1;
- X }
- X#endif
- X
- X return fd;
- X}
- X
- END_OF_FILE
- if test 8775 -ne `wc -c <'copymsg.c'`; then
- echo shar: \"'copymsg.c'\" unpacked with wrong size!
- fi
- # end of 'copymsg.c'
- fi
- echo shar: End of shell archive.
- exit 0
-
-
-